# @Time   : 2022/3/29 14:50
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
"""
轮廓查找新算法,物料区域是白色情况.思路就是先找到上下的轮廓,然后找中间的额黑色图像.黑色图像查找之前要先将轮廓定义处理一下.找到最大的那个.
"""

# @Time   : 2022/3/29 9:52
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^


import time

import cv2
import imutils
import numpy as np

import settings
from tools.config_params import ConfigParams
from vision_process.image_transfer import *
from settings import *

areaFilterUpDown = 500
areaFilterLeftRight = 100000
cp = ConfigParams()
colorBlue = (255, 0, 0)
colorGreen = (0, 255, 0)
colorRed = (0, 0, 255)
lineThickness = 5
colorList = [colorBlue, colorGreen, colorRed]
xPos1 = 1100
xPos2 = 1629

minLineLength = int(30 * cp.mm2pix)  # 线条最短是多少,50个mm
lineLengthMin = 25 * cp.mm2pix
maxLineGap = int(5 * cp.mm2pix)


def image_show(name, image, showState=False):
    """
    显示图片,用来调试的时候显示图片,按照一定的比例进行缩放
    :param name:显示的图片窗口名称
    :param image:显示的图片
    :param showState:是否显示
    :return:
    """
    if showState:
        sizeScale = 4
        newWidth = int(image.shape[1] / sizeScale)
        newHeight = int(image.shape[0] / sizeScale)
        showImage = cv.resize(image, (newWidth, newHeight), cv.INTER_AREA)
        cv.namedWindow("{}".format(name))
        cv.imshow("{}".format(name), showImage)
        cv.waitKey(0)


def get_size_scale_image(imageSrc, sizeScale):
    """
    高宽同等比例缩放图像,缩放比例
    :param imageSrc: 原图像
    :param sizeScale: 缩放比例
    :return:
    """
    h, w = imageSrc.shape[:2]
    newWidth, newHeight = int(w / sizeScale), int(h / sizeScale)
    newImage = cv.resize(imageSrc, (newWidth, newHeight), cv.INTER_AREA)
    return newImage


def get_center_by_contour(contour):
    """
    根据轮廓点获取这个轮廓的中心点
    :param contour:
    :return:
    """
    return int(cv.minAreaRect(contour)[0][0]), int(cv.minAreaRect(contour)[0][1])


def get_two_points_middle(p1, p2):
    """
    获取两个点的中点坐标
    :param p1: 点1
    :param p2: 点2
    :return:
    """
    assert len(p1) == 2
    assert len(p2) == 2
    middleX = (p1[0] + p2[0]) / 2
    middleY = (p1[1] + p2[1]) / 2
    return round(middleX, 2), round(middleY, 2)


def get_line_k_and_b(p1, p2):
    """
    湖区某一条直线的斜率和斜距
    :param p1: 点1的坐标
    :param p2: 点2的坐标
    :return:
    """
    if p1[0] == p2[0]:
        # 垂直于x轴,没有k值
        return None, p1[0]
    else:
        k = (p2[1] - p1[1]) / (p2[0] - p1[0])
        b = p1[1] - k * p1[0]
        return round(k, 2), b


def get_two_lines_intersection(k1, b1, k2, b2):
    """
    获取平面上两条线的交点
    :param k1: 线1的k值
    :param b1: 线1的b值
    :param k2: 线2的k值
    :param b2: 线2的b值
    :return:
    """
    # 如果k相等,说明垂直无交点
    if k1 == k2:
        return None, None
    elif k1 is None and k2 is not None:
        return int(b1), int(k2 * b1 + b2)
    elif k2 is None and k1 is not None:
        return int(b2), int(k1 * b2 + b1)
    else:
        x = (b1 - b2) / (k1 - k2) * (-1)
        y = k1 * x + b1
    return int(x), int(y)


def get_rect_points_clockwise(rectPoints):
    """
    根据矩形的四个顶点,获取其顺时针方向的四个顶点
    :param rectPoints:
    :return:
    """
    rectPointsSorted = sorted(rectPoints, key=np.sum)
    leftTop = rectPointsSorted[0]
    rightBottom = rectPointsSorted[-1]

    if rectPointsSorted[1][0] > rectPointsSorted[2][0]:
        rightTop = rectPointsSorted[1]
        leftBottom = rectPointsSorted[2]
    else:
        rightTop = rectPointsSorted[2]
        leftBottom = rectPointsSorted[1]

    return tuple(leftTop), tuple(rightTop), tuple(rightBottom), tuple(leftBottom)


def get_linear_fit_k_and_b_vertical(pointsMat):
    """
    垂直方向获取拟合直线,因为垂直方向上,有角度可能很接近90度的情况,如果大于一定的值,就认为是None
    :param pointsMat:
    :return:
    """
    outPut = cv.fitLine(pointsMat, cv.DIST_L2, 0, 0.01, 0.01)
    if outPut[0] != 0:
        k = outPut[1] / outPut[0]
        k = k[0]
        if abs(k) > 1000:
            k = None
            b = np.mean(pointsMat, axis=0)[0]
        else:
            b = outPut[3] - k * outPut[2]
    else:
        k = None
        b = outPut[2]
    return float(k) if k is not None else None, float(b)


def find_left_line(leftImage):
    """
    先找左边线,如果左边线找不到,就报警,证明板子倾斜度太大
    :param lefImage:
    :return:
    """
    cv.destroyAllWindows()
    image_show("LeftImage", leftImage)
    imageColor = cv.cvtColor(leftImage, cv.COLOR_GRAY2BGR)
    leftImage = cv.GaussianBlur(leftImage, (0, 0), 5)
    image_show("LeftImageBlurred", leftImage)
    T, board = cv.threshold(leftImage, 50, 255, cv.THRESH_BINARY_INV)
    board = cv.morphologyEx(board, cv.MORPH_CLOSE, (5, 5), iterations=3)
    image_show("leftBoard", board)
    cnts = cv.findContours(board, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    largeContours = [cnt for cnt in cnts if cv.contourArea(cnt) > areaFilterLeftRight]
    if len(largeContours) >= 1:
        largeContoursSorted = sorted(largeContours, key=cv.contourArea, reverse=True)
        contourFinded = largeContoursSorted[0]
        rectPoints = np.int0(cv.boxPoints(cv.minAreaRect(contourFinded)))
        boardColor = imageColor.copy()
        cv.drawContours(boardColor, [np.array(rectPoints)], -1, colorGreen, thickness=3)
        image_show("LeftContour", boardColor)
        box = cv.minAreaRect(contourFinded)
        (cx, cy), (w, h), angle = box
        if angle > 70:
            angle = 90 - angle
            box = (cx, cy), (h, w), angle
        if angle < -70:
            angle = 90 + angle
            box = (cx, cy), (h, w), angle

        leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(cv.boxPoints(box))

        # 这里找到以后,再使用哪个scharrXY再找一次,先将图像抠出来
        sliceX = int(min(leftTop[0], leftBottom[0]))
        sliceX = sliceX - 5 if sliceX > 5 else sliceX  # 如果大于,就再往左边截五个像素
        yStart = int(min(leftTop[1], rightTop[1]))
        yEnd = int(max(leftBottom[1], rightBottom[1]))

        sliceX = sliceX if sliceX >= 0 else 0
        yStart = yStart if yStart >= 0 else 0
        yEnd = yEnd if yEnd <= board.shape[0] else board.shape[0]

        imageUsed = board[yStart:yEnd, sliceX:]
        image_show("ImageUsedFindedLeftLine", imageUsed)
        cv.destroyAllWindows()
        scharrX = cv.Scharr(imageUsed, cv.CV_64F, 1, 0)
        scharrY = cv.Scharr(imageUsed, cv.CV_64F, 0, 1)
        scharrX = cv.convertScaleAbs(scharrX)
        scharrY = cv.convertScaleAbs(scharrY)
        scharrXY = cv.addWeighted(scharrX, 0.3, scharrY, 0.2, 0)
        findLineBoard = scharrXY.copy()
        image_show("ScharrXYLeftLine", findLineBoard)
        lines = cv.HoughLinesP(findLineBoard, 1, np.pi / 180, 100, minLineLength, maxLineGap)
        boardShow = imageColor.copy()
        linesList = []
        linesListTop = []  # 上边的线条
        linesListBottom = []  # 下边的线条
        colorIndex = 0
        xOffset = sliceX
        yOffset = yStart
        if lines is not None:
            for line in lines:
                for x1, y1, x2, y2 in line:
                    lineLength = get_two_point_distance((x1, y1), (x2, y2))
                    xMin = 0
                    xMax = boardShow.shape[1] * 0.8
                    if abs(x2 - x1) < 10 * cp.mm2pix and abs(y2 - y1) > 10 * cp.mm2pix and xMin < x1 < xMax and xMin < x2 < xMax:
                        x1 += xOffset
                        x2 += xOffset
                        y1 += yOffset
                        y2 += yOffset
                        lineTemp = [(x1, y1), (x2, y2)]
                        linesList.append([lineTemp, (x1 + x2) / 2, lineLength])
                        cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 2)
                        colorIndex += 1

                    topLineYMin = 0
                    topLineYMax = imageUsed.shape[0] * 0.3
                    if abs(x2 - x1) > 10 * cp.mm2pix and abs(y2 - y1) < 10 * cp.mm2pix and xMin < x1 < xMax and xMin < x2 < xMax and \
                            topLineYMin < y1 < topLineYMax and topLineYMin < y2 < topLineYMax:
                        x1 += xOffset
                        x2 += xOffset
                        y1 += yOffset
                        y2 += yOffset
                        lineTemp = [(x1, y1), (x2, y2)]
                        linesListTop.append([lineTemp, (y1 + y2) / 2, lineLength])
                        cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 2)
                        colorIndex += 1

                    bottomLineYMin = imageUsed.shape[0] * 0.8
                    bottomLineYMax = imageUsed.shape[0]
                    if abs(x2 - x1) > 10 * cp.mm2pix and abs(y2 - y1) < 10 * cp.mm2pix and xMin < x1 < xMax and xMin < x2 < xMax and \
                            bottomLineYMin < y1 < bottomLineYMax and bottomLineYMin < y2 < bottomLineYMax:
                        x1 += xOffset
                        x2 += xOffset
                        y1 += yOffset
                        y2 += yOffset
                        lineTemp = [(x1, y1), (x2, y2)]
                        linesListBottom.append([lineTemp, (y1 + y2) / 2, lineLength])
                        cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 2)
                        colorIndex += 1

        if len(linesListTop) >= 1:
            image_show("leftLineFinded", boardShow)
            linesSortedLength = sorted(linesListTop, key=lambda x: x[2], reverse=True)
            lineFinalFinded = linesSortedLength[0][0]
            topK, topB = get_line_k_and_b(lineFinalFinded[0], lineFinalFinded[1])
        else:
            topK, topB = get_line_k_and_b(leftTop, rightTop)

        if len(linesListBottom) >= 1:
            image_show("leftLineFinded", boardShow)
            linesSortedLength = sorted(linesListBottom, key=lambda x: x[2], reverse=True)
            lineFinalFinded = linesSortedLength[0][0]
            bottomK, bottomB = get_line_k_and_b(lineFinalFinded[0], lineFinalFinded[1])
        else:
            bottomK, bottomB = get_line_k_and_b(leftBottom, rightBottom)

        if len(linesList) >= 1:
            image_show("leftLineFinded", boardShow)
            linesListSortedX = sorted(linesList, key=lambda x: x[2], reverse=True)
            midIndex = int(len(linesListSortedX) / 2)
            lineFinalFinded = linesListSortedX[0][0]
            leftK, leftB = get_line_k_and_b(lineFinalFinded[0], lineFinalFinded[1])
            # topK,topB = get_line_k_and_b(leftTop,rightTop)
            # bottomK,bottomB = get_line_k_and_b(leftBottom,rightBottom)
            leftTop = get_two_lines_intersection(leftK, leftB, topK, topB)
            leftBottom = get_two_lines_intersection(leftK, leftB, bottomK, bottomB)
        else:
            leftK = get_line_k_and_b(leftTop, leftBottom)[0]

        # 然后重新计算四个点,现在确定的点是leftTop,leftBottom. topK,bottomK
        x = leftImage.shape[1]
        y1 = int(topK * x + topB)
        y2 = int(bottomK * x + bottomB)
        rightTop = (x, y1)
        rightBottom = (x, y2)

        boardShow = imageColor.copy()
        cv.line(boardShow, leftTop, leftBottom, colorGreen, 3)
        cv.line(boardShow, leftTop, rightTop, colorGreen, 3)
        cv.line(boardShow, leftBottom, rightBottom, colorGreen, 3)
        image_show("LeftLineFinalFinded", boardShow)
        angle = get_angle_by_k(leftK)
        if angle < 0:
            angle = angle + 90
        else:
            angle = angle - 90
        print("lefAngle: {}".format(angle))
        leftTopMid = get_two_points_middle(leftTop, rightTop)
        leftBottomMid = get_two_points_middle(leftBottom, rightBottom)
        leftLine = [leftTop, leftBottom]
        leftMid = get_two_points_middle(leftTop, leftBottom)
        if leftMid[0] == 0 or leftTopMid[1] == 0 or leftBottomMid[1] == leftImage.shape[0]:
            return "error", "左边识别的轮廓位置超出边界,请手动移动下板子,然后重新检测!", None, None, None, None
        else:
            leftLine = [[int(p[0]), int(p[1])] for p in leftLine]
            leftTopMid = [int(leftTopMid[0]), int(leftTopMid[1])]
            leftBottomMid = [int(leftBottomMid[0]), int(leftBottomMid[1])]
            return "ok", "左边识别成功", leftLine, leftTopMid, leftBottomMid, angle
    else:
        return "error", "识别失败,左边没有找到任何轮廓", None, None, None, None


def get_two_point_distance(p1, p2):
    """
    获取两点之间的距离,保留小数点后两位
    :param p1: 点1
    :param p2: 点2
    :return:
    """
    assert len(p1) == 2
    assert len(p2) == 2
    ds = np.sqrt((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2)
    return round(ds, 2)


def find_right_line(rightImage, xOffset):
    """
    先找左边线,如果左边线找不到,就报警,证明板子倾斜度太大
    :param lefImage:
    :return:
    """
    cv.destroyAllWindows()
    image_show("RightImage", rightImage)
    imageColor = cv.cvtColor(rightImage, cv.COLOR_GRAY2BGR)
    rightImage = cv.GaussianBlur(rightImage, (0, 0), 5)
    image_show("RightImageOpened", rightImage)
    T, board = cv.threshold(rightImage, 50, 255, cv.THRESH_BINARY_INV)
    board = cv.morphologyEx(board, cv.MORPH_OPEN, (5, 5), iterations=3)
    image_show("rightBoard", board)
    cnts = cv.findContours(board, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    largeContours = [cnt for cnt in cnts if cv.contourArea(cnt) > areaFilterLeftRight]
    if len(largeContours) >= 1:
        largeContoursSorted = sorted(largeContours, key=cv.contourArea, reverse=True)
        contourFinded = largeContoursSorted[0]
        rectPoints = np.int0(cv.boxPoints(cv.minAreaRect(contourFinded)))
        boardColor = imageColor.copy()
        cv.drawContours(boardColor, [np.array(rectPoints)], -1, colorGreen, thickness=3)
        image_show("RightContour", boardColor)
        box = cv.minAreaRect(contourFinded)
        (cx, cy), (w, h), angle = box
        if angle > 70:
            angle = 90 - angle
            box = (cx, cy), (h, w), angle
        if angle < -70:
            angle = 90 + angle
            box = (cx, cy), (h, w), angle

        leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(cv.boxPoints(box))

        sliceX = int(max(rightTop[0], rightBottom[0]))
        sliceX = sliceX + 5 if sliceX + 5 < rightImage.shape[1] else sliceX
        yStart = int(min(leftTop[1], rightTop[1]))
        yEnd = int(max(leftBottom[1], rightBottom[1]))
        yStart = yStart if yStart >= 0 else 0
        yEnd = yEnd if yEnd <= board.shape[0] else board.shape[0]
        imageUsed = board[yStart:yEnd, :sliceX]
        image_show("ImageUsedFindRightLine", imageUsed)
        cv.destroyAllWindows()

        scharrX = cv.Scharr(imageUsed, cv.CV_64F, 1, 0)
        scharrY = cv.Scharr(imageUsed, cv.CV_64F, 0, 1)
        scharrX = cv.convertScaleAbs(scharrX)
        scharrY = cv.convertScaleAbs(scharrY)
        scharrXY = cv.addWeighted(scharrX, 0.5, scharrY, 0.2, 0)
        findLineBoard = scharrXY.copy()
        image_show("ScharrXYLeftLine", findLineBoard)
        lines = cv.HoughLinesP(findLineBoard, 1, np.pi / 180, 100, minLineLength, maxLineGap)
        boardShow = imageColor.copy()
        linesList = []
        linesListTop = []
        linesListBottom = []
        colorIndex = 0
        yOffset = yStart
        if lines is not None:
            for line in lines:
                for x1, y1, x2, y2 in line:
                    lineLength = get_two_point_distance((x1, y1), (x2, y2))
                    xMin = boardShow.shape[1] * 0.1
                    xMax = boardShow.shape[1]
                    if abs(x2 - x1) < 10 * cp.mm2pix and abs(y2 - y1) > 5 * cp.mm2pix and xMin < x1 < xMax and xMin < x2 < xMax:
                        y1 += yOffset
                        y2 += yOffset
                        lineTemp = [(x1, y1), (x2, y2)]
                        linesList.append([lineTemp, (x1 + x2) / 2, lineLength])
                        cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 2)
                        colorIndex += 1

                    topLineYMin = 0
                    topLineYMax = imageUsed.shape[0] * 0.3
                    if abs(x2 - x1) > 10 * cp.mm2pix and abs(y2 - y1) < 10 * cp.mm2pix and xMin < x1 < xMax and xMin < x2 < xMax and \
                            topLineYMin < y1 < topLineYMax and topLineYMin < y2 < topLineYMax:
                        y1 += yOffset
                        y2 += yOffset
                        lineTemp = [(x1, y1), (x2, y2)]
                        linesListTop.append([lineTemp, (y1 + y2) / 2, lineLength])
                        cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 2)
                        colorIndex += 1

                    bottomLineYMin = imageUsed.shape[0] * 0.8
                    bottomLineYMax = imageUsed.shape[0]
                    if abs(x2 - x1) > 10 * cp.mm2pix and abs(y2 - y1) < 10 * cp.mm2pix and xMin < x1 < xMax and xMin < x2 < xMax and \
                            bottomLineYMin < y1 < bottomLineYMax and bottomLineYMin < y2 < bottomLineYMax:
                        y1 += yOffset
                        y2 += yOffset
                        lineTemp = [(x1, y1), (x2, y2)]
                        linesListBottom.append([lineTemp, (y1 + y2) / 2, lineLength])
                        cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 2)
                        colorIndex += 1
        if len(linesListTop) >= 1:
            image_show("rightLineFinded", boardShow)
            linesSortedLength = sorted(linesListTop, key=lambda x: x[2], reverse=True)
            lineFinalFinded = linesSortedLength[0][0]
            topK, topB = get_line_k_and_b(lineFinalFinded[0], lineFinalFinded[1])
        else:
            topK, topB = get_line_k_and_b(leftTop, rightTop)

        if len(linesListBottom) >= 1:
            image_show("rightLineFinded", boardShow)
            linesSortedLength = sorted(linesListBottom, key=lambda x: x[2], reverse=True)
            lineFinalFinded = linesSortedLength[0][0]
            bottomK, bottomB = get_line_k_and_b(lineFinalFinded[0], lineFinalFinded[1])
        else:
            bottomK, bottomB = get_line_k_and_b(leftBottom, rightBottom)

        if len(linesList) >= 1:
            image_show("rightLineFinded", boardShow)
            linesListSortedX = sorted(linesList, key=lambda x: x[2], reverse=True)
            midIndex = int(len(linesListSortedX) / 2)
            lineFinalFinded = linesListSortedX[0][0]
            rightK, rightB = get_line_k_and_b(lineFinalFinded[0], lineFinalFinded[1])
            # topK, topB = get_line_k_and_b(leftTop, rightTop)
            # bottomK, bottomB = get_line_k_and_b(leftBottom, rightBottom)
            rightTop = get_two_lines_intersection(rightK, rightB, topK, topB)
            rightBottom = get_two_lines_intersection(rightK, rightB, bottomK, bottomB)
        else:
            rightK = get_line_k_and_b(rightTop, rightBottom)[0]

        # 现在确定的点是rightTop,rightBottom,还设有topK,topB,bottomK,bottomB
        x = 0
        y1 = int(topK * x + topB)
        y2 = int(bottomK * x + bottomB)
        leftTop = (x, y1)
        leftBottom = (x, y2)

        boardShow = imageColor.copy()
        cv.line(boardShow, rightTop, rightBottom, colorGreen, 3)
        cv.line(boardShow, leftTop, rightTop, colorGreen, 3)
        cv.line(boardShow, leftBottom, rightBottom, colorGreen, 3)
        image_show("rightLineFinalFinded", boardShow)

        angle = get_angle_by_k(rightK)
        if angle < 0:
            angle = angle + 90
        else:
            angle = angle - 90
        print("RightAngle: {}".format(angle))
        rightTopMid = get_two_points_middle(leftTop, rightTop)
        rightBottomMid = get_two_points_middle(leftBottom, rightBottom)
        rightLine = [rightTop, rightBottom]
        rigthMid = get_two_points_middle(rightTop, rightBottom)
        if rigthMid[0] == rightImage.shape[1] or rightTopMid[1] == 0 or rightBottomMid[1] == rightImage.shape[0]:
            return "error", "右边识别的轮廓位置超出边界,请手动移动下板子,然后重新检测!", None, None, None, None
        else:
            # 将左边转换到大图上去,就是y方向的偏移问题
            rightLine = [[int(rightLine[0][0] + xOffset), int(rightLine[0][1])], [int(rightLine[1][0] + xOffset), int(rightLine[1][1])]]
            rightTopMid = int(rightTopMid[0] + xOffset), int(rightTopMid[1])
            rightBottomMid = int(rightBottomMid[0] + xOffset), int(rightBottomMid[1])
            return "ok", "右边识别成功", rightLine, rightTopMid, rightBottomMid, angle
    else:
        return "error", "识别失败,右边没有找到任何轮廓", None, None, None, None


def get_board_without_angle(image, boxMaster, extend=0):
    """
    获取无角度的物料区域,是否延长,表示是否延长物料区域的四周,保证可以完整的看到物料区域.extend表示延长多少的意思.
    :param image:
    :param boxMaster:
    :param extend:延长多少的标识,0表示不延长
    :return:
    """
    (centerX, centerY), (w, h), angle = boxMaster
    widthHalf = int(w / 2)
    heightHalf = int(h / 2)
    yStart = max(int(centerY - heightHalf), 0)  # 之所以有零的情况,是因为旋转之后物料框的y起点可能跑到外面去了.
    yEnd = min(int(centerY + heightHalf), image.shape[0])  # yEnd也是一样的,有可能出去了
    xStart = max(int(centerX - widthHalf), 0)
    xEnd = min(int(centerX + widthHalf), image.shape[1])
    M = cv.getRotationMatrix2D((centerX, centerY), angle, 1)
    if extend != 0:
        if yStart - extend > 0:
            yStart = yStart - extend
        if yEnd + extend < image.shape[0]:
            yEnd = yEnd + extend

        if xStart - extend > 0:
            xStart = xStart - extend
        if xStart + extend < image.shape[1]:
            xEnd = xEnd + extend

    totalBoard = cv.warpAffine(image, M, (image.shape[1], image.shape[0]))[yStart:yEnd, xStart:xEnd]
    return totalBoard, [xStart, yStart]


def find_total_board_info_4pin(image):
    if settings.TemplateImage is not None:
        templateImage = get_image_used(settings.TemplateImage)
        imageSub = cv2.subtract(image.copy(),templateImage)
        imageSliceY = imageSub.copy()
    else:
        imageSliceY = image.copy()
    image_show("ImageOriginal", image)
    # Y轴方向上的截取位置
    cv.destroyAllWindows()
    imageColor = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
    # 先把图像分成左右两个部分
    # 中间的两个型材位置
    # 将中间的部分填充为黑色.
    imageSliceY[:, xPos1:xPos2] = 0
    image_show("FillBlack", imageSliceY)

    # 获取平均亮度
    meanVal = int(np.mean(imageSliceY))
    print("平均亮度: {}".format(meanVal))
    if meanVal > 100:
        thresUsed = 90
    else:
        # 然后整个图去找轮廓
        thresUsed = 50
    T, board = cv.threshold(imageSliceY, thresUsed, 255, cv.THRESH_BINARY)
    image_show("BoardThres", board)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
    board = cv.morphologyEx(board, cv.MORPH_OPEN, kernel, iterations=5)

    image_show("BoardOpened", board)
    # T,totalBoardThres = cv.threshold(image,60,255,cv.THRESH_BINARY_INV)
    # totalBoardThres = board.copy()
    # image_show("TotalBoardThres", totalBoardThres)

    cnts = cv.findContours(board.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)

    largeContours = [cnt for cnt in cnts if cv.contourArea(cnt) > areaFilterLeftRight]
    print("Contours Finded = {}".format([cv.contourArea(cnt) for cnt in largeContours]))

    if len(largeContours) >= 2:
        # largeContours = sorted(largeContours, key=cv.contourArea, reverse=True)[:2]  # 只取前面两个最大的
        centerPoints = [get_center_by_contour(contour) for contour in largeContours]
        centerXmin = 150
        centerXmax = board.shape[1] - 100
        centerYmin = 150
        centerYMax = board.shape[0] - 100
        centerPointsValid = [center for center in centerPoints if (centerXmax > center[0] > centerXmin and centerYMax > center[1] > centerYmin)]
        print("centerPoints: {},centerPointsValid: {}".format(centerPoints,centerPointsValid))
        centerPoints = centerPointsValid
        # 过去掉假的中心点,边缘轮廓太低的去除掉
        for index, center in enumerate(centerPoints):
            anotherCenter = centerPoints[(index + 1) % len(centerPoints)]
            cv.line(board, center, anotherCenter, 255, 20)
            image_show("JointCenterLine", board)

        cnts = cv.findContours(board.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
        cnts = imutils.grab_contours(cnts)
        cntFirstFinded = sorted(cnts, key=cv.contourArea, reverse=True)[0]
    elif len(largeContours) == 1:
        cntFirstFinded = largeContours[0]
    else:
        info = "没有找到任何的轮廓,考虑板子没有到位或者的光源坏了."
        return "error", info, None, None, imageColor

    rectPoints = np.int0(cv.boxPoints(cv.minAreaRect(cntFirstFinded)))
    leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectPoints)
    # board = cv.drawContours(board,[np.array([leftTop,rightTop,rightBottom,leftBottom])],-1,255,-1)
    # image_show("BoardFillWhite",board)
    boardFinal = board.copy()
    # 将中间黑色区域填充成白色
    # startY = max(leftTop[1],rightTop[1]) + int(50 * cp.mm2pix)
    # endY = min(leftBottom[1],rightBottom[1]) - int(50 * cp.mm2pix)
    # if startY <= endY:
    #     boardFinal[startY:endY,xPos1:xPos2] = 255
    moveWidth = int(get_two_point_distance(leftTop, rightTop) * 0.15)
    moveHeight = int(get_two_point_distance(leftTop, leftBottom) * 0.15)
    extend = 30

    boardFinal[leftTop[1] - extend:leftTop[1] + moveHeight, leftTop[0] - extend:leftTop[0] + moveWidth] = 0
    boardFinal[rightTop[1] - extend:rightTop[1] + moveHeight, rightTop[0] - moveWidth:rightTop[0] + extend] = 0
    boardFinal[leftBottom[1] - moveHeight:leftBottom[1] + extend, leftBottom[0] - extend:leftBottom[0] + moveWidth] = 0
    boardFinal[rightBottom[1] - moveHeight:rightBottom[1] + extend, rightBottom[0] - moveWidth:rightBottom[0] + extend] = 0
    image_show("FinalBoardAngleMoved", boardFinal)

    cnts = cv.findContours(boardFinal.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    largeContours = [cnt for cnt in cnts if cv.contourArea(cnt) > areaFilterLeftRight]

    if len(largeContours) >= 1:
        largeContours = sorted(largeContours, key=cv.contourArea, reverse=True)  # 只取前面两个最大的
        cntFinalFinded = largeContours[0]
    else:
        info = "没有找到任何的轮廓,考虑板子没有到位或者的光源坏了."
        return "error", info, None, None, imageColor

    # 然后就是四条边线重新去找,如何去找呢?就是要截取出来重新找
    box = cv.minAreaRect(cntFinalFinded)
    (cx, cy), (w, h), boxAngle = box
    if boxAngle > 70:
        angleNew = 90 - boxAngle
        box = (cx, cy), (h, w), angleNew

    if boxAngle < -70:
        angleNew = 90 + boxAngle
        box = (cx, cy), (h, w), angleNew

    rectPoints = np.int0(cv.boxPoints(cv.minAreaRect(cntFinalFinded)))
    imageShow = imageColor.copy()
    leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectPoints)
    cv.drawContours(imageShow, [rectPoints], -1, colorGreen, 3)
    image_show("ContourFindedFinal", imageShow)

    # cv.drawContours(totalBoardThres, cntFinalFinded, -1, 255, -1)

    # totalBoardNoAngle, totalBoardOffset = get_board_without_angle(image, box)
    # findEdgeExtend = int(2 * cp.mm2pix)
    # totalBoardExtendForFindEdge, _ = get_board_without_angle(image, box, findEdgeExtend)
    # totalBoardThresForFindEdge, _ = get_board_without_angle(totalBoardThres, box, findEdgeExtend)
    #
    # topLineK, topLineB = find_first_edge_line(image, totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend, totalBoardOffset, box)
    # if topLineK is None and topLineB is None:
    topLineK, topLineB = get_line_k_and_b(leftTop, rightTop)
    # bottomLineK, bottomLineB = find_third_edge_line(totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend, totalBoardOffset, box)
    # if bottomLineK is None and bottomLineB is None:
    bottomLineK, bottomLineB = get_line_k_and_b(leftBottom, rightBottom)

    # leftLineK, leftLineB = find_left_edge_line(totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend, totalBoardOffset, box)
    # if leftLineK is None and leftLineB is None:
    leftLineK, leftLineB = get_line_k_and_b(leftTop, leftBottom)

    # rightLineK, rightLineB = find_right_edge_line(totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend, totalBoardOffset, box)
    # if rightLineK is None and rightLineB is None:
    rightLineK, rightLineB = get_line_k_and_b(rightTop, rightBottom)

    leftTop = get_two_lines_intersection(leftLineK, leftLineB, topLineK, topLineB)
    rightTop = get_two_lines_intersection(rightLineK, rightLineB, topLineK, topLineB)
    leftBottom = get_two_lines_intersection(leftLineK, leftLineB, bottomLineK, bottomLineB)
    rightBottom = get_two_lines_intersection(rightLineK, rightLineB, bottomLineK, bottomLineB)
    print("四个顶点数据：", leftTop, rightTop, rightBottom, leftBottom)
    #
    # H, W = image.shape[:2]
    # # 找到这几个点的极值点,如果超过了图像的范围,就报错,认为坐标有错误
    # if leftTop[0] < 0 or leftTop[1] < 0 or rightTop[0] > W or rightTop[1] < 0 or leftBottom[0] < 0 or leftBottom[1] > H or rightBottom[0] > W or rightBottom[1] > H:
    #     info = "计算的轮廓四个顶点超出了图像边界,图像错误"
    #     return "error", info, None, None, imageColor

    cv.drawContours(imageColor, [np.array([leftTop, rightTop, rightBottom, leftBottom])], -1, colorGreen, 3)
    image_show("FourLineFinalFinded", imageColor)

    # leftK, leftB = get_line_k_and_b(leftTop, leftBottom)
    # rightK, rightB = get_line_k_and_b(rightTop, rightBottom)
    leftAngle = get_angle_by_k(leftLineK)
    rightAngle = get_angle_by_k(rightLineK)

    if leftAngle < 0:
        leftAngle = leftAngle + 90
    else:
        leftAngle = leftAngle - 90

    if rightAngle < 0:
        rightAngle = rightAngle + 90
    else:
        rightAngle = rightAngle - 90

    # 根据左右图的坐标,计算大图的坐标:
    angleMean = round((leftAngle + rightAngle) / 2, 3)
    print("Angle: {},LeftAngle: {},RightAngle: {}".format(angleMean,leftAngle,rightAngle))
    # leftLine = [leftTop, leftBottom]
    # rightLine = [rightTop, rightBottom]
    # topK, topB = get_line_k_and_b(leftTop, rightTop)

    # topLine要做延长的
    # topK, topB = get_line_k_and_b(leftTopMid, rightTopMid)
    # bottomK, bottomB = get_line_k_and_b(leftBottomMid, rightBottomMid)
    # leftK, leftB = get_line_k_and_b(leftLine[0], leftLine[1])
    # rightK, rightB = get_line_k_and_b(rightLine[0], rightLine[1])
    #
    # leftTopIntersection = get_two_lines_intersection(leftK, leftB, topK, topB)
    # rightTopIntersection = get_two_lines_intersection(rightK, rightB, topK, topB)
    # leftBottomIntersection = get_two_lines_intersection(leftK, leftB, bottomK, bottomB)
    # rightBottomIntersection = get_two_lines_intersection(rightK, rightB, bottomK, bottomB)
    #
    # topLine = [leftTop, rightTop]
    # bottomLine = [leftBottom, rightBottom]
    #
    # cv.line(imageColor, tuple(leftLine[0]), tuple(leftLine[1]), colorGreen, thickness=3)
    # cv.line(imageColor, tuple(rightLine[0]), tuple(rightLine[1]), colorGreen, thickness=3)
    # cv.line(imageColor, tuple(topLine[0]), tuple(topLine[1]), colorGreen, thickness=5)
    # cv.line(imageColor, tuple(bottomLine[0]), tuple(bottomLine[1]), colorGreen, thickness=3)
    # image_show("TotalContourFinded", imageColor)

    boardHeight = round((get_two_point_distance(leftTop,leftBottom) + get_two_point_distance(rightTop,rightBottom)) / 2 / cp.mm2pix,2)
    print("boardHeight: {}".format(boardHeight))

    if boardHeight <= cp.smallBoardRange:
        # 如果是小板就抓取中心点
        yOffset = int(boardHeight / 2 * cp.mm2pix)
    else:
        # 固定边的偏移值
        yOffset = int(cp.catchPosOffset4pin * cp.mm2pix)
    fixLineMid = get_two_points_middle(leftBottom, rightBottom)
    # 固定边是topLine,按照这个line做垂线
    if bottomLineK is None:
        verK = 0
        verB = fixLineMid[1] - verK * fixLineMid[0]
        catchY = fixLineMid[1] - abs(yOffset * np.sin(trans_k_to_rad(verK)))
        catchX = verB
    elif bottomLineK == 0:
        catchX = fixLineMid[0]
        catchY = fixLineMid[1] - yOffset
    else:
        verK = -1 / bottomLineK
        verB = fixLineMid[1] - verK * fixLineMid[0]
        catchY = fixLineMid[1] - abs(yOffset * np.sin(trans_k_to_rad(verK)))
        catchX = (catchY - verB) / verK

    catchPos = (int(catchX), int(catchY))
    print(catchX, catchY)
    interSection5 = np.int0(fixLineMid)

    cv.line(imageColor, tuple(interSection5), catchPos, colorRed, lineThickness)
    cv.circle(imageColor, catchPos, 5, colorBlue, -1)
    cv.putText(imageColor, "angle:{:.2f}".format(angleMean), (catchPos[0] - 50, catchPos[1] - 200),
               cv.FONT_HERSHEY_SIMPLEX, 2, colorBlue, 4)
    cv.putText(imageColor, "catchPos:{}".format(catchPos), (catchPos[0] - 50, catchPos[1] - 30),
               cv.FONT_HERSHEY_SIMPLEX, 2, colorBlue, 4)
    heightPos = get_two_points_middle(leftTop,leftBottom)
    cv.putText(imageColor,"H:{} mm".format(boardHeight),(int(heightPos[0]),int(heightPos[1])),
               cv.FONT_HERSHEY_SIMPLEX,2,colorBlue,4)
    print("Angle: {:.2f},catchPos:{}".format(angleMean, catchPos))

    image_show("TotalBoard", imageColor)

    catchPosRobot = get_module_catch_pos(catchPos)
    if ROBOT_LIMIT_X_MIN < catchPosRobot[0] < ROBOT_LIMIT_X_MAX and ROBOT_LIMIT_Y_MIN < catchPosRobot[1] < ROBOT_LIMIT_Y_Max and \
            abs(angleMean) < cp.errorAngleThres:
        return "ok", "识别成功!", catchPosRobot, angleMean, imageColor
    elif abs(angleMean) >= cp.errorAngleThres:
        return "error", "识别的角度太大,识别角度:{:.2f},阈值:{:.2f}".format(angleMean, cp.errorAngleThres), catchPosRobot, angleMean, imageColor
    else:
        info = "识别的坐标超过极限位置,识别的抓取坐标X:{:.2f},ok范围:({},{}),坐标Y:{:.2f},ok范围:({},{})".format(
            catchPosRobot[0], ROBOT_LIMIT_X_MIN, ROBOT_LIMIT_X_MAX, catchPosRobot[1], ROBOT_LIMIT_Y_MIN, ROBOT_LIMIT_Y_Max)
        return "error", info, catchPosRobot, angleMean, imageColor

    # # 获取抓取位置偏移
    # yOffset = int(cp.catchPosOffset4pin * cp.mm2pix)
    #
    # fixK, fixB = get_line_k_and_b(interSection3, interSection4)
    # # 做右边线的垂线,根据那个补偿值
    # fixLineMid = get_two_points_middle(interSection3, interSection4)
    # print(fixK, fixB)
    # print(fixLineMid)
    # if fixK == 0:
    #     catchX = fixLineMid[0]
    #     catchY = fixLineMid[1] - yOffset
    # else:
    #     verK = -1 / fixK
    #     verB = fixLineMid[1] - verK * fixLineMid[0]
    #     catchY = fixLineMid[1] - abs(yOffset * np.sin(trans_k_to_rad(verK)))
    #     catchX = (catchY - verB) / verK
    #
    # # if meanLineK is None:
    # #     fixMiddle = get_two_points_middle(interSection3, interSection4)
    # #     catchX = fixMiddle[0]
    # #     catchY = fixMiddle[1] - yOffset
    # # else:
    # #     fixMiddle = get_two_points_middle(interSection3, interSection4)
    # #     # catchX = fixMiddle[0] - abs(yOffset * np.cos(trans_k_to_rad(meanLineK)))
    # #     # catchY = meanLineK * catchX + meanLineB
    # #     catchY = fixMiddle[1] - abs(yOffset * np.sin(trans_k_to_rad(meanLineK)))
    # #     catchX = (catchY - meanLineB) / meanLineK
    # # if angle < 0:
    # #     angle = round(angle + 90, 2)
    # # else:
    # #     angle = round(angle - 90, 2)
    # print(catchX, catchY)
    #
    # catchPos = (int(catchX), int(catchY))
    # # 和固定边的交点
    # interSection5 = np.int0(fixLineMid)
    # # (x,y)坐标颠倒
    # # interSection5 = (interSection5[1],interSection5[0])
    #
    # cv.line(imageColorContour, tuple(interSection5), catchPos, colorRed, lineThickness)
    # cv.circle(imageColorContour, catchPos, 5, colorRed, -1)
    # cv.putText(imageColorContour, "angle:{:.2f}".format(angle), (catchPos[0] - 100, catchPos[1] - 200),
    #            cv.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 0), 4)
    # cv.putText(imageColorContour, "catchPos:{}".format(catchPos), (catchPos[0] - 100, catchPos[1] - 30), cv.FONT_HERSHEY_SIMPLEX,
    #            2, (255, 0, 0), 4)
    # print("Angle: {:.2f},catchPos:{}".format(angle, catchPos))
    # image_show("TotalBoard", imageColorContour)
    #
    # # 根据图像抓取位置,获取实际的坐标偏移
    # catchPosRobot = get_module_catch_pos(catchPos)
    # if ROBOT_LIMIT_X_MIN < catchPosRobot[0] < ROBOT_LIMIT_X_MAX and ROBOT_LIMIT_Y_MIN < catchPosRobot[1] < ROBOT_LIMIT_Y_Max and \
    #         abs(angle) < cp.errorAngleThres:
    #     return "ok", "识别成功!", catchPosRobot, angle, imageColorContour
    # elif abs(angle) >= cp.errorAngleThres:
    #     return "error","识别的角度太大,识别角度:{:.2f},阈值:{:.2f}".format(angle,cp.errorAngleThres),catchPosRobot,angle,imageColorContour
    # else:
    #     info = "识别的坐标超过极限位置,识别的抓取坐标X:{:.2f},ok范围:({},{}),坐标Y:{:.2f},ok范围:({},{})".format(
    #         catchPosRobot[0],ROBOT_LIMIT_X_MIN,ROBOT_LIMIT_X_MAX,catchPosRobot[1],ROBOT_LIMIT_Y_MIN,ROBOT_LIMIT_Y_Max)
    #     return "error",info , catchPosRobot, angle, imageColorContour


def find_third_edge_line(image,totalBoard, totalBoardThres, extend, totalBoardOffset, box):
    """
    找物料区域的第一边
    :param totalBoard:totalBoard延长了上下左右
    :param totalBoardThres: totalBoardThres延长了上下左右
    :param extend: 延长的尺寸
    :return:
    """
    try:
        cv.destroyAllWindows()
        imageColor = cv.cvtColor(image,cv.COLOR_GRAY2BGR)
        totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
        image_show("TotalBoardThres", totalBoardThres)
        ySlice = int(totalBoardThres.shape[0] / 2)
        board = totalBoardThres.copy()[ySlice:, :]
        scharrX = cv.Scharr(board, cv.CV_64F, 1, 0)
        scharrY = cv.Scharr(board, cv.CV_64F, 0, 1)
        scharrX = cv.convertScaleAbs(scharrX)
        scharrY = cv.convertScaleAbs(scharrY)
        scharrXY = cv.addWeighted(scharrX, 0.3, scharrY, 0.5, 0)
        board = scharrXY.copy()
        image_show("ScharrXYEdgeThirdLine", board)
        minLineLenghtEdge = int(8 * cp.mm2pix)
        maxLineGap = 30
        xMin = int(30 * cp.mm2pix)
        xMax = int(totalBoardThres.shape[1] - int(30 * cp.mm2pix))
        yMin = board.shape[0] - 200 * cp.mm2pix
        yMax = board.shape[0]
        lines = cv.HoughLinesP(board, 1, np.pi / 180, 150, minLineLenghtEdge, maxLineGap)
        boardShow = totalBoardColor.copy()
        pointList = []
        colorIndex = 0
        if lines is not None:
            for line in lines:
                for x1, y1, x2, y2 in line:
                    lineLength = get_two_point_distance((x1, y1), (x2, y2))
                    if (abs(y2 - y1) < 20 * cp.mm2pix and abs(x2 - x1) > 5 * cp.mm2pix and yMin < y1 < yMax and yMin < y2 < yMax
                      and xMin < x1 < xMax and xMin < x2 < xMax and lineLength > minLineLenghtEdge):
                        y1 += ySlice
                        y2 += ySlice
                        point = int((x1 + x2) / 2),int((y1 + y2 )/ 2)
                        pointList.append([point, (y1 + y2) / 2])
                        cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 3)
                        colorIndex += 1
        # 先按照y进行排序,然后截取前面的1/2进行判断.注意两个点代表一条线,截取掉的个数要是偶数
        if len(pointList) >= 2:
            pointSortedY = sorted(pointList, key=lambda x: x[1])
            pointMiddleIndex = len(pointSortedY) // 2
            linesFinal = pointSortedY[pointMiddleIndex][0],pointSortedY[pointMiddleIndex + 1][0]
            image_show("EdgeFinded", boardShow)
            # 然后再按照线段的长度进行排序
            # linesSortedLength = sorted(linesList, key=lambda x: x[2], reverse=True)
            # print("linesSortedLength: 个数:{}, {}".format(len(linesSortedLength), linesSortedLength))
            # linesList = linesSortedLength.copy()
            # linesFinal = linesSortedLength[0]
            print("ThirdLine最后找到的线段的坐标为({},{})".format(linesFinal[0], linesFinal[1]))
            boardShow = totalBoardColor.copy()
            p1, p2 = linesFinal
            cv.line(boardShow, tuple(p1), tuple(p2), colorBlue, 3)
            image_show("FinalLineFindedThird", boardShow)
            # 将延长的去除掉,图像别延长了,要放到延长之前的图上去,y坐标要去除掉之前增加的部分
            p1, p2 = (p1[0] - extend, p1[1] - extend), (p2[0] - extend, p2[1] - extend)
            rotatedCenter, (w, h), rotatedAngle = box
            M = cv.getRotationMatrix2D(rotatedCenter, -rotatedAngle, 1)
            centerOffset = totalBoardOffset
            p1Big = np.dot(M, [p1[0] + centerOffset[0], p1[1] + centerOffset[1], 1])
            p2Big = np.dot(M, [p2[0] + centerOffset[0], p2[1] + centerOffset[1], 1])
            cv.line(imageColor, (int(p1Big[0]), int(p1Big[1])), (int(p2Big[0]), int(p2Big[1])), colorBlue, 3)
            image_show("FinalLineFindedThirdBig",imageColor)
            topCutLineK, topCutLineB = get_line_k_and_b(p1Big, p2Big)
            return topCutLineK, topCutLineB
        else:
            return None, None
    except Exception as e:
        errorInfo = "in find_third_edge_line() error: {}".format(str(e))
        print(errorInfo)
        return None, None


def find_first_edge_line(image, totalBoard, totalBoardThres, extend, totalBoardOffset, box):
    """
    找物料区域的第一边
    :param totalBoard:totalBoard延长了上下左右
    :param totalBoardThres: totalBoardThres延长了上下左右
    :param extend: 延长的尺寸
    :return:
    """
    try:
        cv2.destroyAllWindows()
        imageColor = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
        totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
        image_show("TotalBoardThres", totalBoardThres)
        board = totalBoardThres.copy()[:int(totalBoardThres.shape[0] / 2), :]
        scharrX = cv.Scharr(board, cv.CV_64F, 1, 0)
        scharrY = cv.Scharr(board, cv.CV_64F, 0, 1)
        scharrX = cv.convertScaleAbs(scharrX)
        scharrY = cv.convertScaleAbs(scharrY)
        scharrXY = cv.addWeighted(scharrX, 0.3, scharrY, 0.5, 0)
        board = scharrXY.copy()
        image_show("ScharrXYEdgeFindFirstLine", board)
        minLineLenghtEdge = int(10 * cp.mm2pix)
        maxLineGap = 30
        xMin = 30 * cp.mm2pix
        xMax = totalBoardThres.shape[1] - 30 * cp.mm2pix
        yMin = 1 * cp.mm2pix
        yMax = 200 * cp.mm2pix
        lines = cv.HoughLinesP(board, 1, np.pi / 180, 150, minLineLenghtEdge, maxLineGap)
        boardShow = totalBoardColor.copy()
        pointList = []
        colorIndex = 0
        if lines is not None:
            for line in lines:
                for x1, y1, x2, y2 in line:
                    lineLength = get_two_point_distance((x1, y1), (x2, y2))
                    if (abs(y2 - y1) < 20 * cp.mm2pix and abs(x2 - x1) > 5 * cp.mm2pix and yMin < y1 < yMax and yMin < y2 < yMax
                      and xMin < x1 < xMax and xMin < x2 < xMax  and lineLength > minLineLenghtEdge):
                        point = (int((x1+x2) / 2),int((y1 + y2)/2))
                        pointList.append([point, (y1 + y2) / 2])
                        cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 3)
                        colorIndex += 1
        # 先按照y进行排序,然后截取前面的1/2进行判断.注意两个点代表一条线,截取掉的个数要是偶数

        # linesSortedLength = linesList.copy()
        # 然后再按照线段的长度进行排序
        # linesSortedLength = sorted(linesList, key=lambda x: x[2], reverse=True)
        # print("linesSortedLength: 个数:{}, {}".format(len(linesSortedLength), linesSortedLength))
        # linesList = linesSortedLength.copy()
        if len(pointList) >= 2:
            pointSortedY = sorted(pointList, key=lambda x: x[1],reverse=True)
            pointMiddleIndex = len(pointSortedY) // 2  # 用中间的那条线来作为最后的结果
            image_show("EdgeFinded", boardShow)
            linesFinal = pointSortedY[pointMiddleIndex][0],pointSortedY[pointMiddleIndex + 1][0]
            print("最后找到的线段的坐标为({},{})".format(linesFinal[0],linesFinal[1]))
            boardShow = totalBoardColor.copy()
            p1, p2 = linesFinal
            cv.line(boardShow, tuple(p1), tuple(p2), colorBlue, 3)
            image_show("FinalLineFinded", boardShow)
            # 将延长的去除掉,图像别延长了,要放到延长之前的图上去,y坐标要去除掉之前增加的部分
            p1, p2 = (p1[0] - extend, p1[1] - extend), (p2[0] - extend, p2[1] - extend)
            rotatedCenter, (w, h), rotatedAngle = box
            M = cv.getRotationMatrix2D(rotatedCenter, -rotatedAngle, 1)
            centerOffset = totalBoardOffset
            p1Big = np.dot(M, [p1[0] + centerOffset[0], p1[1] + centerOffset[1], 1])
            p2Big = np.dot(M, [p2[0] + centerOffset[0], p2[1] + centerOffset[1], 1])
            cv.line(imageColor, (int(p1Big[0]), int(p1Big[1])), (int(p2Big[0]), int(p2Big[1])), colorBlue, 3)
            image_show("FinalLineFindedFirstBig", imageColor)
            topCutLineK, topCutLineB = get_line_k_and_b(p1Big, p2Big)
            return topCutLineK, topCutLineB
        else:
            return None, None
    except Exception as e:
        errorInfo = "in find_first_edge_line() error: {}".format(str(e))
        print(errorInfo)
        return None, None


def find_left_edge_line(image,totalBoard, totalBoardThres, extend, totalBoardOffset, box):
    """
    找左边的那条线条
    :param totalBoard:
    :param totalBoardThres:
    :param extend:
    :param totalBoardOffset:
    :param box:
    :return:
    """
    try:
        cv.destroyAllWindows()
        imageColor = cv.cvtColor(image,cv.COLOR_GRAY2BGR)
        totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
        image_show("TotalBoardThresFindLeft", totalBoardThres)
        board = totalBoardThres.copy()[:,:totalBoardThres.shape[1] // 3]
        scharrX = cv.Scharr(board, cv.CV_64F, 1, 0)
        scharrY = cv.Scharr(board, cv.CV_64F, 0, 1)
        scharrX = cv.convertScaleAbs(scharrX)
        scharrY = cv.convertScaleAbs(scharrY)
        scharrXY = cv.addWeighted(scharrX, 0.5, scharrY, 0.3, 0)
        board = scharrXY.copy()
        image_show("ScharrXYEdgeFindLeft", board)
        minLineLenghtEdge = int(8 * cp.mm2pix)
        maxLineGap = 50
        yMin = int(80 * cp.mm2pix)
        yMax = totalBoardThres.shape[0] - int(80 * cp.mm2pix)
        xMin = 1 * cp.mm2pix
        xMax = xPos1 - totalBoardOffset[0] - int(50 * cp.mm2pix)
        lines = cv.HoughLinesP(board, 1, np.pi / 180, 150, minLineLenghtEdge, maxLineGap)
        boardShow = totalBoardColor.copy()
        pointList = []
        colorIndex = 0
        if lines is not None:
            for line in lines:
                for x1, y1, x2, y2 in line:
                    lineLength = get_two_point_distance((x1, y1), (x2, y2))
                    if (abs(x2 - x1) < 20 * cp.mm2pix and abs(y2 - y1) > 8 * cp.mm2pix and  xMin < x1 < xMax
                      and xMin < x2 < xMax and  yMin < y1 < yMax and yMin < y2 < yMax and lineLength > minLineLenghtEdge):
                        point = int((x1 + x2) / 2) ,int((y1+y2) /2)
                        pointList.append([point, (x1 + x2) / 2])
                        cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 3)
                        colorIndex += 1

        if len(pointList) >= 2:
            # 先按照y进行排序,然后截取前面的1/2进行判断.注意两个点代表一条线,截取掉的个数要是偶数
            pointSortedX = sorted(pointList, key=lambda x: x[1],reverse=True)
            middleIndex = len(pointSortedX) // 2
            linesFinal = pointSortedX[middleIndex][0],pointSortedX[middleIndex + 1][0]
            image_show("EdgeFindedLeft", boardShow)
            # # 然后再按照线段的长度进行排序
            # linesSortedLength = sorted(linesList, key=lambda x: x[2], reverse=True)
            # print("linesSortedLength: 个数:{}, {}".format(len(linesSortedLength), linesSortedLength))
            # linesList = linesSortedLength.copy()
            print("leftLine最后线段坐标为({},{})".format(linesFinal[0],linesFinal[1]))
            boardShow = totalBoardColor.copy()
            p1, p2 = linesFinal
            cv.line(boardShow, tuple(p1), tuple(p2), colorBlue, 3)
            image_show("FinalLineFindedLeft", boardShow)
            # 将延长的去除掉,图像别延长了,要放到延长之前的图上去,y坐标要去除掉之前增加的部分
            p1, p2 = (p1[0] - extend, p1[1] - extend), (p2[0] - extend, p2[1] - extend)
            rotatedCenter, (w, h), rotatedAngle = box
            M = cv.getRotationMatrix2D(rotatedCenter, -rotatedAngle, 1)
            centerOffset = totalBoardOffset
            p1Big = np.dot(M, [p1[0] + centerOffset[0], p1[1] + centerOffset[1], 1])
            p2Big = np.dot(M, [p2[0] + centerOffset[0], p2[1] + centerOffset[1], 1])
            cv2.line(imageColor,(int(p1Big[0]),int(p1Big[1])),(int(p2Big[0]),int(p2Big[1])),
                     colorBlue,3)
            image_show("LeftLineFindedBig",imageColor)
            leftCutLineK, leftCutLineB = get_line_k_and_b(p1Big, p2Big)
            return leftCutLineK, leftCutLineB
        else:
            return None, None
    except Exception as e:
        errorInfo = "in find_left_edge_line() error: {}".format(str(e))
        print(errorInfo)
        return None, None


def find_right_edge_line(image,totalBoard, totalBoardThres, extend, totalBoardOffset, box):
    """
    找左边的那条线条
    :param totalBoard:
    :param totalBoardThres:
    :param extend:
    :param totalBoardOffset:
    :param box:
    :return:
    """
    try:
        cv.destroyAllWindows()
        imageColor = cv.cvtColor(image,cv2.COLOR_GRAY2BGR)
        totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
        image_show("TotalBoardThresFindRight", totalBoardThres)
        board = totalBoardThres.copy()
        scharrX = cv.Scharr(board, cv.CV_64F, 1, 0)
        scharrY = cv.Scharr(board, cv.CV_64F, 0, 1)
        scharrX = cv.convertScaleAbs(scharrX)
        scharrY = cv.convertScaleAbs(scharrY)
        scharrXY = cv.addWeighted(scharrX, 0.5, scharrY, 0.3, 0)
        board = scharrXY.copy()
        image_show("ScharrXYEdgeFindRight", board)
        minLineLenghtEdge = int(8 * cp.mm2pix)
        maxLineGap = int(8*cp.mm2pix)
        xMin = xPos2 - totalBoardOffset[0] + int(50 * cp.mm2pix)
        yMin = int(80 * cp.mm2pix)
        yMax = totalBoardThres.shape[0] - int(80 * cp.mm2pix)
        lines = cv.HoughLinesP(board, 1, np.pi / 180, 150, minLineLenghtEdge, maxLineGap)
        boardShow = totalBoardColor.copy()
        pointList = []
        colorIndex = 0
        if lines is not None:
            for line in lines:
                for x1, y1, x2, y2 in line:
                    lineLength = get_two_point_distance((x1, y1), (x2, y2))
                    if (abs(x2 - x1) < 20 * cp.mm2pix and abs(y2 - y1) > 5 * cp.mm2pix and xMin < x1 and xMin < x2
                    and yMin   < y1 < yMax and yMin < y2 < yMax
                      and lineLength > minLineLenghtEdge):
                        point = int((x1 + x2 )/2),int((y1 + y2) / 2)
                        angle = get_angle_by_k(get_line_k_and_b((x1,y1),(x2,y2))[0])
                        pointList.append([point, (x1 + x2) / 2,angle])
                        cv.line(boardShow, (x1, y1), (x2, y2), colorList[colorIndex % 3], 3)
                        colorIndex += 1

        if len(pointList) >= 2:
            # 先按照x进行排序,然后截取前面的1/2进行判断.注意两个点代表一条线,截取掉的个数要是偶数
            pointListSortedX = sorted(pointList, key=lambda x: x[1])
            linesMidIndex = len(pointListSortedX) // 2
            print("PointListSortedX: {}".format(pointListSortedX))
            lineFinal = pointListSortedX[linesMidIndex][0],pointListSortedX[linesMidIndex + 1][0]
            image_show("EdgeFindedRight", boardShow)
            # # 然后再按照线段的长度进行排序
            # linesSortedLength = sorted(linesList, key=lambda x: x[2], reverse=True)
            # print("linesSortedLength: 个数:{}, {}".format(len(linesSortedLength), linesSortedLength))
            # linesList = linesSortedLength.copy()
            # linesFinal = linesSortedLength[0]
            print("rightLine最后线段坐标为:({},{})".format(lineFinal[0],lineFinal[1]))
            boardShow = totalBoardColor.copy()
            p1, p2 = lineFinal
            cv.line(boardShow, tuple(p1), tuple(p2), colorBlue, 3)
            image_show("FinalLineFindedRight", boardShow)
            # 将延长的去除掉,图像别延长了,要放到延长之前的图上去,y坐标要去除掉之前增加的部分
            p1, p2 = (p1[0] - extend, p1[1] - extend), (p2[0] - extend, p2[1] - extend)
            rotatedCenter, (w, h), rotatedAngle = box
            M = cv.getRotationMatrix2D(rotatedCenter, -rotatedAngle, 1)
            centerOffset = totalBoardOffset
            p1Big = np.dot(M, [p1[0] + centerOffset[0], p1[1] + centerOffset[1], 1])
            p2Big = np.dot(M, [p2[0] + centerOffset[0], p2[1] + centerOffset[1], 1])
            cv2.line(imageColor, (int(p1Big[0]), int(p1Big[1])), (int(p2Big[0]), int(p2Big[1])),
                     colorBlue, 3)
            image_show("RightLineFindedBig",imageColor)
            leftCutLineK, leftCutLineB = get_line_k_and_b(p1Big, p2Big)
            return leftCutLineK, leftCutLineB
        else:
            return None, None
    except Exception as e:
        errorInfo = "in find_left_edge_line() error: {}".format(str(e))
        print(errorInfo)
        return None, None


def find_total_board_info_6pin(image):
    # Y轴方向上的截取位置
    cv.destroyAllWindows()
    imageSliceY = image.copy()
    image_show("ImageOriginal", imageSliceY)
    imageColor = cv.cvtColor(imageSliceY, cv.COLOR_GRAY2BGR)
    # 先把图像分成左右两个部分
    # 中间的两个型材位置
    # 将中间的部分填充为黑色.
    image[:, xPos1:xPos2] = 255
    image_show("FillWhite", image)

    # 然后整个图去找轮廓
    thresUsed = cp.thresUsed
    T, board = cv.threshold(image, thresUsed, 255, cv.THRESH_BINARY_INV)
    image_show("BoardThres", board)
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
    # 进行腐蚀,让其分开
    board = cv.morphologyEx(board, cv.MORPH_ERODE, kernel, iterations=10)
    image_show("BoardErode", board)
    # T,totalBoardThres = cv.threshold(image,60,255,cv.THRESH_BINARY_INV)
    totalBoardThres = board.copy()
    image_show("TotalBoardThres", totalBoardThres)

    cnts = cv.findContours(board.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)

    largeContours = [cnt for cnt in cnts if cv.contourArea(cnt) > areaFilterLeftRight]
    print("Contours Finded = {}".format([cv.contourArea(cnt) for cnt in largeContours]))

    if len(largeContours) >= 2:
        # largeContours = sorted(largeContours, key=cv.contourArea, reverse=True)[:2]  # 只取前面两个最大的
        centerPoints = [get_center_by_contour(contour) for contour in largeContours]
        centerXmin = 150
        centerXmax = board.shape[1] - 150
        centerYmin = 150
        centerYMax = board.shape[0] - 150
        centerPointsValid = [center for center in centerPoints if (centerXmax > center[0] > centerXmin and centerYMax > center[1] > centerYmin)]
        print("centerPoints: {},centerPointsValid: {}".format(centerPoints, centerPointsValid))
        centerPoints = centerPointsValid
        # 过去掉假的中心点,边缘轮廓太低的去除掉
        for index, center in enumerate(centerPoints):
            anotherCenter = centerPoints[(index + 1) % len(centerPoints)]
            cv.line(board, center, anotherCenter, 255, 20)
            image_show("JointCenterLine", board)
        cnts = cv.findContours(board.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
        cnts = imutils.grab_contours(cnts)
        cntFirstFinded = sorted(cnts, key=cv.contourArea, reverse=True)[0]
    elif len(largeContours) == 1:
        cntFirstFinded = largeContours[0]
    else:
        info = "没有找到任何的轮廓,考虑板子没有到位或者的光源坏了."
        return "error", info, None, None, imageColor

    rectPoints = np.int0(cv.boxPoints(cv.minAreaRect(cntFirstFinded)))
    leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectPoints)
    # mask = np.zeros(board.shape,np.uint8)
    # board = cv.drawContours(mask ,[np.array([leftTop,rightTop,rightBottom,leftBottom])],-1,255,-1)
    board = cv.morphologyEx(board, cv.MORPH_DILATE, kernel, iterations=3)
    image_show("BoardFillWhite",board)
    boardFinal = board.copy()
    moveWidth = int(get_two_point_distance(leftTop, rightTop) * 0.1)
    moveHeight = int(get_two_point_distance(leftTop, leftBottom) * 0.2)
    extend = 30

    boardFinal[leftTop[1] - extend:leftTop[1] + moveHeight, leftTop[0] - extend:leftTop[0] + moveWidth] = 0
    boardFinal[rightTop[1] - extend:rightTop[1] + moveHeight, rightTop[0] - moveWidth:rightTop[0] + extend] = 0
    boardFinal[leftBottom[1] - moveHeight:leftBottom[1] + extend, leftBottom[0] - extend:leftBottom[0] + moveWidth] = 0
    boardFinal[rightBottom[1] - moveHeight:rightBottom[1] + extend, rightBottom[0] - moveWidth:rightBottom[0] + extend] = 0
    image_show("FinalBoardAngleMoved", boardFinal)

    cnts = cv.findContours(boardFinal.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    largeContours = [cnt for cnt in cnts if cv.contourArea(cnt) > areaFilterLeftRight]

    if len(largeContours) >= 1:
        largeContours = sorted(largeContours, key=cv.contourArea, reverse=True)  # 只取前面两个最大的
        cntFinalFinded = largeContours[0]
    else:
        info = "没有找到任何的轮廓,考虑板子没有到位或者的光源坏了."
        return "error", info, None, None, imageColor

    # 然后就是四条边线重新去找,如何去找呢?就是要截取出来重新找
    box = cv.minAreaRect(cntFinalFinded)
    (cx, cy), (w, h), boxAngle = box
    if boxAngle > 70:
        angleNew = 90 - boxAngle
        box = (cx, cy), (h, w), angleNew

    if boxAngle < -70:
        angleNew = 90 + boxAngle
        box = (cx, cy), (h, w), angleNew

    rectPoints = np.int0(cv.boxPoints(cv.minAreaRect(cntFinalFinded)))
    imageShow = imageColor.copy()
    leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectPoints)
    cv.drawContours(imageShow, [rectPoints], -1, colorGreen, 3)
    image_show("ContourFindedFinal", imageShow)

    # cv.drawContours(totalBoardThres, cntFinalFinded, -1, 255, -1)

    totalBoardNoAngle, totalBoardOffset = get_board_without_angle(image, box)
    findEdgeExtend = int(2 * cp.mm2pix)
    totalBoardExtendForFindEdge, _ = get_board_without_angle(image, box, findEdgeExtend)
    totalBoardThresForFindEdge, _ = get_board_without_angle(totalBoardThres, box, findEdgeExtend)

    # topLineK, topLineB = find_first_edge_line(image, totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend, totalBoardOffset, box)
    # if topLineK is None and topLineB is None:
    #     topLineK, topLineB = get_line_k_and_b(leftTop, rightTop)
    # bottomLineK, bottomLineB = find_third_edge_line(image,totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend, totalBoardOffset, box)
    # if bottomLineK is None and bottomLineB is None:
    #     bottomLineK, bottomLineB = get_line_k_and_b(leftBottom, rightBottom)
    #
    # leftLineK, leftLineB = find_left_edge_line(image,totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend, totalBoardOffset, box)
    # if leftLineK is None and leftLineB is None:
    #     leftLineK, leftLineB = get_line_k_and_b(leftTop, leftBottom)
    #
    # rightLineK, rightLineB = find_right_edge_line(image,totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend, totalBoardOffset, box)
    # if rightLineK is None and rightLineB is None:
    #     rightLineK, rightLineB = get_line_k_and_b(rightTop, rightBottom)

    topLineK, topLineB = get_line_k_and_b(leftTop, rightTop)
    bottomLineK, bottomLineB = get_line_k_and_b(leftBottom, rightBottom)
    leftLineK, leftLineB = get_line_k_and_b(leftTop, leftBottom)
    rightLineK, rightLineB = get_line_k_and_b(rightTop, rightBottom)
    leftTop = get_two_lines_intersection(leftLineK, leftLineB, topLineK, topLineB)
    rightTop = get_two_lines_intersection(rightLineK, rightLineB, topLineK, topLineB)
    leftBottom = get_two_lines_intersection(leftLineK, leftLineB, bottomLineK, bottomLineB)
    rightBottom = get_two_lines_intersection(rightLineK, rightLineB, bottomLineK, bottomLineB)

    print(leftTop, rightTop, rightBottom, leftBottom)
    # H, W = image.shape[:2]
    # # 找到这几个点的极值点,如果超过了图像的范围,就报错,认为坐标有错误
    # if leftTop[0] < 0 or leftTop[1] < 0 or rightTop[0] > W or rightTop[1] < 0 or leftBottom[0] < 0 or leftBottom[1] > H or rightBottom[0] > W or rightBottom[1] > H:
    #     info = "计算的轮廓四个顶点超出了图像边界,图像错误"
    #     return "error", info, None, None, imageColor

    boardHeight = round((get_two_point_distance(leftTop, leftBottom) + get_two_point_distance(rightTop, rightBottom)) / 2 / cp.mm2pix, 2)
    print("boardHeight: {}".format(boardHeight))

    if boardHeight <= cp.smallBoardRange:
        # 如果是小板就抓取中心点
        # xOffset = int(boardHeight / 2 * cp.mm2pix)
        xOffset = int(cp.catchPosOffset6pin * cp.mm2pix)
    else:
        # 固定边的偏移值
        xOffset = int(cp.catchPosOffset6pin * cp.mm2pix)

    cv.drawContours(imageColor, [np.array([leftTop, rightTop, rightBottom, leftBottom])], -1, colorGreen, 3)
    image_show("FourLineFinalFinded", imageColor)

    leftK, leftB = get_line_k_and_b(leftTop, leftBottom)
    rightK, rightB = get_line_k_and_b(rightTop, rightBottom)
    leftAngle = get_angle_by_k(leftK)
    rightAngle = get_angle_by_k(rightK)

    if leftAngle < 0:
        leftAngle = leftAngle + 90
    else:
        leftAngle = leftAngle - 90

    if rightAngle < 0:
        rightAngle = rightAngle + 90
    else:
        rightAngle = rightAngle - 90

    # 根据左右图的坐标,计算大图的坐标:
    angleMean = round((leftAngle + rightAngle) / 2, 3)
    # leftLine = [leftTop, leftBottom]
    # rightLine = [rightTop, rightBottom]
    # topK, topB = get_line_k_and_b(leftTop, rightTop)

    # topLine要做延长的
    # topK, topB = get_line_k_and_b(leftTopMid, rightTopMid)
    # bottomK, bottomB = get_line_k_and_b(leftBottomMid, rightBottomMid)
    # leftK, leftB = get_line_k_and_b(leftLine[0], leftLine[1])
    # rightK, rightB = get_line_k_and_b(rightLine[0], rightLine[1])
    #
    # leftTopIntersection = get_two_lines_intersection(leftK, leftB, topK, topB)
    # rightTopIntersection = get_two_lines_intersection(rightK, rightB, topK, topB)
    # leftBottomIntersection = get_two_lines_intersection(leftK, leftB, bottomK, bottomB)
    # rightBottomIntersection = get_two_lines_intersection(rightK, rightB, bottomK, bottomB)
    #
    # topLine = [leftTop, rightTop]
    # bottomLine = [leftBottom, rightBottom]
    #
    # cv.line(imageColor, tuple(leftLine[0]), tuple(leftLine[1]), colorGreen, thickness=3)
    # cv.line(imageColor, tuple(rightLine[0]), tuple(rightLine[1]), colorGreen, thickness=3)
    # cv.line(imageColor, tuple(topLine[0]), tuple(topLine[1]), colorGreen, thickness=5)
    # cv.line(imageColor, tuple(bottomLine[0]), tuple(bottomLine[1]), colorGreen, thickness=3)
    # image_show("TotalContourFinded", imageColor)

    # 固定边的偏移值
    # xOffset = int(cp.catchPosOffset6pin * cp.mm2pix)
    # fixLineMid = get_two_points_middle(leftTop, leftBottom)
    fixLineMid = get_two_points_middle(rightTop, rightBottom)
    # 固定边是topLine,按照这个line做垂线
    if leftLineK is None:
        catchX = fixLineMid[0] - xOffset
        catchY = fixLineMid[1]
    else:
        verK = -1 / leftLineK
        verB = fixLineMid[1] - verK * fixLineMid[0]
        # catchX = fixLineMid[0] + abs(xOffset * np.cos(trans_k_to_rad(verK)))
        catchX = fixLineMid[0] - abs(xOffset * np.cos(trans_k_to_rad(verK)))
        catchY = verK * catchX + verB

    catchPos = (int(catchX), int(catchY))
    print(catchX, catchY)
    interSection5 = np.int0(fixLineMid)

    cv.line(imageColor, tuple(interSection5), catchPos, colorRed, lineThickness)
    cv.circle(imageColor, catchPos, 5, colorRed, -1)
    cv.putText(imageColor, "angle:{:.2f}".format(angleMean), (catchPos[0] - 50, catchPos[1] - 200),
               cv.FONT_HERSHEY_SIMPLEX, 2, colorRed, 4)
    cv.putText(imageColor, "catchPos:{}".format(catchPos), (catchPos[0] - 50, catchPos[1] - 30),
               cv.FONT_HERSHEY_SIMPLEX, 2, colorRed, 4)
    heightPos = get_two_points_middle(rightTop, rightBottom)
    cv.putText(imageColor, "H:{} mm".format(boardHeight), (int(heightPos[0]), int(heightPos[1])),
               cv.FONT_HERSHEY_SIMPLEX, 2, colorBlue, 4)
    print("Angle: {:.2f},catchPos:{}".format(angleMean, catchPos))

    image_show("TotalBoard", imageColor)

    catchPosRobot = get_module_catch_pos(catchPos)
    if ROBOT_LIMIT_X_MIN < catchPosRobot[0] < ROBOT_LIMIT_X_MAX and ROBOT_LIMIT_Y_MIN < catchPosRobot[1] < ROBOT_LIMIT_Y_Max and \
            abs(angleMean) < cp.errorAngleThres:
        return "ok", "识别成功!", catchPosRobot, angleMean, imageColor
    elif abs(angleMean) >= cp.errorAngleThres:
        return "error", "识别的角度太大,识别角度:{:.2f},阈值:{:.2f}".format(angleMean, cp.errorAngleThres), catchPosRobot, angleMean, imageColor
    else:
        info = "识别的坐标超过极限位置,识别的抓取坐标X:{:.2f},ok范围:({},{}),坐标Y:{:.2f},ok范围:({},{})".format(
            catchPosRobot[0], ROBOT_LIMIT_X_MIN, ROBOT_LIMIT_X_MAX, catchPosRobot[1], ROBOT_LIMIT_Y_MIN, ROBOT_LIMIT_Y_Max)
        return "error", info, catchPosRobot, angleMean, imageColor


def get_module_catch_pos(catchPos):
    # 抓取的图像位置
    catchXpix, catchYPix = catchPos
    # 图像x轴和y轴对应机械手x轴和y轴,只是图像的x轴和机械手的x轴的正负是反的,y轴的正方向和机械手的正方向也是反的.

    imageOffsetX = (catchXpix - cp.centerImageX) / cp.mm2pix  # 转换成mm,坐标值越大的时候,这个偏移是正,到下面要减
    imageOffsetY = (catchYPix - cp.centerImageY) / cp.mm2pix  # 转换成mm,坐标值越大的时候,这个偏移是正,到下面要减

    print("像素偏移：", imageOffsetX, imageOffsetY)
    # 实际的抓板位置
    catchPosX = cp.centerModuleX - imageOffsetY
    catchPosY = cp.centerModuleY - imageOffsetX
    return [int(catchPosX), int(catchPosY)]


def trans_k_to_rad(k):
    """
    将斜率转换为弧度
    :param k: 斜率k值
    :return:
    """
    return np.arctan(k)


def get_angle_by_k(k):
    """
    根据斜率k值,获取对应的角度值
    :param k: 线条的斜率k值
    :return:
    """
    if k == 0:
        return 0
    if k is None:
        return 90
    return np.arctan(k) * 180 / np.pi


def get_mean_angle(leftLine, rightLine):
    """
    获取角平分线
    :param k1:
    :param b1:
    :param k2:
    :param b2:
    :return:
    """
    # 坐标先颠倒,垂直方向的角平分线有点问题
    leftPoints = [(p[1], p[0]) for p in leftLine]
    rightPoints = [(p[1], p[0]) for p in rightLine]
    k1, b1 = get_line_k_and_b(leftPoints[0], leftPoints[1])
    k2, b2 = get_line_k_and_b(rightPoints[0], rightPoints[1])

    intersection = get_two_lines_intersection(k1, b1, k2, b2)
    # 如果本身就是平行线没有交点.这样中线的k就是upK 或者downK,都一样,如果确定b的值呢.
    if intersection[0] is None:
        middleLineK = k1
        y1 = b1
        y2 = b2
        if middleLineK is not None:
            # 先找到中线上的一个必过点
            middleLineP = (0, (y1 + y2) / 2)
            middleLineB = middleLineP[1] - middleLineK * middleLineP[0]
        else:
            middleLineK = None
            middleLineB = (y1 + y2) / 2
    else:
        if k1 is not None and k2 is None:
            middleLineK = np.tan((np.pi / 2 + np.arctan(k1)) / 2)
        elif k1 is None and k2 is not None:
            middleLineK = np.tan((np.pi / 2 + np.arctan(k2)) / 2)
        else:
            middleLineK = np.tan((np.arctan(k1) + np.arctan(k2)) / 2)  # 角平分线公式
        middleLineB = intersection[1] - middleLineK * intersection[0]

    return middleLineK, middleLineB


def get_ver_line_intersection(k1, b1, point):
    """
    获取一个点和一条直线的垂直交点
    :param k1:
    :param b1:
    :param point:
    :return:
    """
    if k1 is None:
        intersection = (int(b1), int(point[1]))
    elif k1 == 0:
        intersectionX = int(point[0])
        intersectionY = int(b1)
        intersection = (intersectionX, intersectionY)
    else:
        verK = -1 / k1
        verB = point[1] - verK * point[0]
        intersection = get_two_lines_intersection(k1, b1, verK, verB)
    return intersection


def distance(p1, p2):
    """
    计算平面上两个点之前的距离,精确到小数点后两位
    :param p1: 平面上的点1
    :param p2: 平面上的点2
    :return:
    """
    assert len(p1) == 2
    assert len(p2) == 2
    return round(np.sqrt((abs(p2[0] - p1[0]) ** 2 + abs(p2[1] - p1[1]) ** 2)), 2)


# def get_image_used(image, gray=False):
#     if not gray:
#         image = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
#     newImage = rotate_image_no_scale(image, -90)  # 逆时针旋转90度.
#     yStart, yEnd = [400, 3449]
#     newImage = newImage[yStart:yEnd, :]
#     # yStart,yEnd,xStart,xEnd = [589,3000,123,2023]
#     # newImage = newImage[yStart:yEnd,xStart:xEnd]
#     return newImage

def get_image_used(image):
    # image = cv.cvtColor(image,cv.COLOR_RGB2GRAY)
    newImage = rotate_image_no_scale(image, -90)  # 时针旋转90度.
    # yStart, yEnd = [415, 3249]
    # newImage = newImage[yStart:yEnd,:]
    yStart, yEnd, xStart, xEnd = [481, 3429, 161, 2905]
    newImage = newImage[yStart:yEnd, xStart:xEnd]
    return newImage


if __name__ == '__main__':
    filePath = r"D:\raw\RawError"
    keepDir = filePath
    if not os.path.isdir(keepDir):
        keepDir, _ = os.path.split(filePath)

    keepOkPath = os.path.join(keepDir, "ok")
    keepOkResPath = os.path.join(keepDir, "res")
    keepFailPath = os.path.join(keepDir, "fail")
    keepFailResPath = os.path.join(keepDir, "fail_res")
    if not os.path.exists(keepOkPath):
        os.makedirs(keepOkPath)
    if not os.path.exists(keepOkResPath):
        os.makedirs(keepOkResPath)
    if not os.path.exists(keepFailPath):
        os.makedirs(keepFailPath)
    if not os.path.exists(keepFailResPath):
        os.makedirs(keepFailResPath)

    width = 1174
    height = 1550
    jointNumber = "4"

    fileNames = []  # 保存要去识别的所有的图片
    if os.path.isfile(filePath):
        filePath, fileName = os.path.split(filePath)
        fileNames.append(fileName)
    else:
        for root, dirs, files in os.walk(filePath):
            if root != filePath:
                continue
            for file in files:
                if file[-4:] != ".bmp":
                    continue
                fileNames.append(file)
    for index, fileName in enumerate(fileNames):
        print("图像名称:{} ".format(fileName))
        filePathReal = os.path.join(filePath, fileName)
        imageTest = cv.imread(filePathReal, cv.IMREAD_GRAYSCALE)
        # print("ImageTest.shape = {},TemplateImage.shape = {}".format(imageTest.shape,TemplateImage.shape))
        # imageSub = cv2.subtract(imageTest,TemplateImage)
        # image_show("ImageSub",imageSub)
        # imageTest = get_size_scale_image(imageTest, 1 / 3)
        imageUsed = get_image_used(imageTest)
        # imageUsed = imageTest.copy()
        calcStart = time.time()
        if jointNumber == "4":
            res, info, center, angle, imageRes = find_total_board_info_4pin(imageUsed)
        else:
            res, info, center, angle, imageRes = find_total_board_info_6pin(imageUsed)
        if res == "ok":
            print("算法耗时: {}".format(time.time() - calcStart))
            os.remove(filePathReal)
            imageRes = get_size_scale_image(imageRes, sizeScale=4)
            cv.imwrite(os.path.join(keepOkResPath, fileName), imageRes)
            cv.imwrite(os.path.join(keepOkPath, fileName), imageTest)
            print("识别成功")
            continue
        else:
            os.remove(filePathReal)
            cv.imwrite(os.path.join(keepFailPath, fileName), imageTest)
            cv.imwrite(os.path.join(keepFailResPath, fileName), imageRes)
            print("算法耗时: {}".format(time.time() - calcStart))
            print("识别失败:{}".format(info))
